#include <iostream>
#include <string>
#include <optional>
#include <vector>
#include <fstream>
#include <memory>
#include <chrono>

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <boost/json.hpp>
#include <fmt/chrono.h>
#include <fmt/format.h>
#include <fmt/compile.h>

namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::asio;
namespace json = boost::json;
using tcp = net::ip::tcp;
namespace chrono = std::chrono;

// 将毫秒时间戳转换为东八区的日期时间字符串
std::string TimestampToDateTime(const int64_t milliseconds) {
    try {
        // 直接构造系统时钟时间点，自动处理精度转换
        const auto time_point = chrono::system_clock::time_point{
            chrono::milliseconds(milliseconds)
        };

        // 直接计算 UTC+8 时间
        const auto eastern8_time = time_point + chrono::hours(8);

        // 转换为 time_t 类型
        const std::time_t eastern8_t = chrono::system_clock::to_time_t(eastern8_time);

        // 转换为本地时间结构
        std::tm tm{};
#ifdef _WIN32
        gmtime_s(&tm, &eastern8_t);
#else
        gmtime_r(&eastern8_t, &tm);
#endif

        // 使用 fmt 库格式化为字符串
        return fmt::format("{:%Y-%m-%d %H:%M:%S}", tm);
    } catch (const std::exception &e) {
        std::cerr << "Error formatting time: " << e.what() << std::endl;
        return "Error";
    }
}

// 从字符串中提取两个标记之间的子串
std::optional<std::string> SubstringBetween(
    const std::string &input,
    const std::string &start_marker,
    const std::string &end_marker) {
    const size_t start_pos = input.find(start_marker);
    if (start_pos == std::string::npos) {
        return std::nullopt; // 未找到起始标记
    }

    const size_t content_start = start_pos + start_marker.length();
    const size_t end_pos = input.find(end_marker, content_start);
    if (end_pos == std::string::npos) {
        return std::nullopt; // 未找到结束标记
    }

    return input.substr(content_start, end_pos - content_start);
}

// 定义CSV行结构
struct WaterLevelData {
    std::string station; // 站点名称
    std::string timestamp; // 时间戳(格式化后)
    std::string level; // 水位
};

// 解析气象数据JSON数组并存储到vector中
std::vector<WaterLevelData> ParseWeatherJson(const std::string &json_str) {
    std::vector<WaterLevelData> result;

    try {
        json::value parsed_value = json::parse(json_str);
        if (!parsed_value.is_array()) {
            std::cerr << "错误：JSON格式不是数组" << std::endl;
            return result;
        }

        for (const auto &item: parsed_value.as_array()) {
            if (!item.is_object()) continue;
            const json::object &obj = item.as_object();

            // 提取并验证必要字段
            const auto stnm_it = obj.find("stnm");
            const auto tm_it = obj.find("tm");
            const auto z_it = obj.find("z");

            if (stnm_it != obj.end() && tm_it != obj.end() && z_it != obj.end()) {
                WaterLevelData data;
                data.station = stnm_it->value().as_string();
                data.timestamp = TimestampToDateTime(tm_it->value().as_int64());
                data.level = z_it->value().as_string();

                result.push_back(data);

                // 控制台输出
                std::cout << "------------------------\n";
                std::cout << "站点: " << data.station << "\n";
                std::cout << "时间: " << data.timestamp << "\n";
                std::cout << "水位: " << data.level << "\n";
            }
        }
    } catch (const std::exception &e) {
        std::cerr << "JSON解析异常: " << e.what() << std::endl;
    }

    return result;
}

// 将数据追加到CSV文件（文件名固定，自动处理表头）
bool WriteToCsv(const std::vector<WaterLevelData> &data, const std::string &filename) {
    if (data.empty()) {
        std::cerr << "警告：没有数据可导出" << std::endl;
        return false;
    }

    try {
        // 1. 先检查文件是否存在且为空
        bool fileIsEmpty = true; {
            std::ifstream checkFile(filename);
            fileIsEmpty = !checkFile.good() || checkFile.peek() == std::ifstream::traits_type::eof();
        }

        // 2. 以追加模式打开文件
        std::ofstream file(filename, std::ios::app);
        if (!file.is_open()) {
            std::cerr << "错误：无法打开文件 " << filename << std::endl;
            return false;
        }

        // 使用RAII确保文件在作用域结束时关闭
        struct FileCloser {
            std::ofstream &file;
            ~FileCloser() { if (file.is_open()) file.close(); }
        } fileCloser{file};

        // 如果文件为空，写入CSV表头
        if (fileIsEmpty) {
            file << "站点名称,时间,水位\n";
        }

        // 写入数据行（添加采集日期列）
        for (const auto &[station, timestamp, level]: data) {
            // 转义CSV字段的工具函数
            auto escapeCsvField = [](const std::string &field) {
                std::string result = field;
                // 替换双引号为两个双引号
                size_t pos = 0;
                while ((pos = result.find('"', pos)) != std::string::npos) {
                    result.replace(pos, 1, "\"\"");
                    pos += 2;
                }
                // 包含特殊字符时用双引号包裹
                if (result.find(',') != std::string::npos ||
                    result.find('"') != std::string::npos ||
                    result.find('\n') != std::string::npos) {
                    return "\"" + result + "\"";
                }
                return result;
            };

            // 拼接完整行（添加采集日期列）
            file << escapeCsvField(station) << ","
                    << escapeCsvField(timestamp) << ","
                    << escapeCsvField(level) << "\n";
        }

        // 检查写入是否成功
        if (!file.good()) {
            std::cerr << "错误：写入文件时发生错误 " << filename << std::endl;
            return false;
        }

        std::cout << "成功追加 " << data.size() << " 条记录到 " << filename << std::endl;
        return true;
    } catch (const std::exception &e) {
        std::cerr << "写入CSV异常: " << e.what() << std::endl;
        return false;
    }
}

// 从URL获取内容 - 使用更安全的异常处理
std::string FetchUrlContent(
    const std::string &host,
    const std::string &path,
    const std::string &port = "80") {
    try {
        // 使用智能指针管理I/O上下文和套接字
        auto io_context = std::make_unique<net::io_context>();
        auto socket = std::make_unique<tcp::socket>(*io_context);

        // 解析主机地址
        tcp::resolver resolver(*io_context);
        const auto endpoints = resolver.resolve(host, port);

        // 连接服务器
        net::connect(*socket, endpoints);

        // 构造HTTP请求
        http::request<http::empty_body> request{http::verb::get, path, 11};
        request.set(http::field::host, host);
        request.set(http::field::user_agent, "Boost.Beast/1.88");
        request.set(http::field::accept, "text/html");
        request.set(http::field::accept_language, "zh-CN");

        // 发送请求
        http::write(*socket, request);

        // 接收响应
        beast::flat_buffer buffer;
        http::response<http::dynamic_body> response;
        http::read(*socket, buffer, response);

        // 关闭连接
        beast::error_code ec;
        socket->shutdown(tcp::socket::shutdown_both, ec);
        if (ec && ec != beast::errc::not_connected) {
            throw beast::system_error{ec};
        }

        // 检查响应状态
        if (response.result() != http::status::ok) {
            throw std::runtime_error("HTTP请求失败: " +
                                     std::to_string(static_cast<int>(response.result())));
        }

        return beast::buffers_to_string(response.body().data());
    } catch (const std::exception &e) {
        // 添加更多上下文信息
        throw std::runtime_error("获取URL内容失败 (" + host + path + "): " + e.what());
    }
}

int main() {
    try {
        constexpr char kTargetHost[] = "www.cjh.com.cn";
        constexpr char kTargetPath[] = "/sqindex.html";
        constexpr char kCsvFilename[] = "water_level_data.csv";

        // 获取网页内容
        std::cout << "正在获取 " << kTargetHost << kTargetPath << " ...\n";
        const std::string content = FetchUrlContent(kTargetHost, kTargetPath);
        std::cout << "成功获取内容，长度: " << content.size() << " 字节\n";

        // 提取气象数据JSON
        constexpr char kJsonStartMarker[] = "var sssq =";
        constexpr char kJsonEndMarker[] = ";";

        const auto json_opt = SubstringBetween(content, kJsonStartMarker, kJsonEndMarker);
        if (!json_opt.has_value()) {
            std::cerr << "错误：未找到水文数据JSON\n";
            return 1;
        }

        // 解析水文数据
        std::cout << "开始解析水文数据...\n";
        std::vector<WaterLevelData> waterData = ParseWeatherJson(json_opt.value());

        // 导出到CSV
        if (!waterData.empty()) {
            if (WriteToCsv(waterData, kCsvFilename)) {
                std::cout << "数据已成功导出到 " << kCsvFilename << std::endl;
            } else {
                std::cerr << "导出CSV文件失败" << std::endl;
            }
        } else {
            std::cerr << "警告：未解析到任何水文数据" << std::endl;
        }

        return 0;
    } catch (const std::exception &e) {
        std::cerr << "程序异常: " << e.what() << std::endl;
        return 1;
    }
};